#include"Variant.h"
using std::string;

namespace
{
	const char vEmptyBuffer[ sizeof(Variant) ] = { 0 };

	template< typename T > 
	void Assign(void* _pDst ,const void* _pSrc )
	{ 
		*(T*)_pDst = *(T*)_pSrc;
	}
}

Variant::Variant()
{
	m_nType = CT_INT;
	memset(m_vBuf,0,sizeof(m_vBuf));
}

Variant::~Variant()
{
	if( m_nType == CT_STR )
		((string*)(m_vBuf))->~string();
}

Variant& Variant::operator = ( const Variant& _V )
{
	if( m_nType == CT_STR &&  _V.m_nType == CT_STR )
	{
		*((string*)(m_vBuf)) = *((string*)(_V.m_vBuf));
	}
	else if( m_nType != CT_STR &&  _V.m_nType == CT_STR )
	{
		new(m_vBuf)string();
		*((string*)(m_vBuf)) = *((string*)(_V.m_vBuf));
	}
	else if( m_nType == CT_STR &&  _V.m_nType != CT_STR )
	{
		((string*)(m_vBuf))->~string();
		memcpy(m_vBuf,_V.m_vBuf,sizeof(m_vBuf));
	}
	else
	{
		memcpy(m_vBuf,_V.m_vBuf,sizeof(m_vBuf));
	}
	m_nType = _V.m_nType;
	return *this;
}


Variant::Variant( const Variant& _V )
{
	if( _V.m_nType == CT_STR )
	{
		new(m_vBuf)string();
		*((string*)(m_vBuf)) = *((string*)(_V.m_vBuf));
	}
	else
	{
		memcpy(m_vBuf,_V.m_vBuf,sizeof(m_vBuf));
	}
	m_nType = _V.m_nType;
}

int Variant::toInt() const
{
	return m_nType == CT_INT ? *(int*)m_vBuf : 0;
}


float Variant::toFloat() const 
{
	return m_nType == CT_FLOAT ? *(float*)m_vBuf : 0.0f;
}

const char* Variant::toStr() const
{ 
	return m_nType == CT_STR ? ((string*)m_vBuf)->c_str() : (const char*)vEmptyBuffer;
}

int Variant::GetType() const
{ 
	return m_nType;
}


void Variant::Set( int _Value )
{
	if(m_nType == CT_STR)
		((string*)(m_vBuf))->~string();
	m_nType = CT_INT;
	*(int*)m_vBuf = _Value;
}

void Variant::Set( float _Value )
{
	if(m_nType == CT_STR)
		((string*)(m_vBuf))->~string();
	m_nType = CT_FLOAT;
	*(float*)m_vBuf = _Value;
}

void Variant::Set( const char* _Value )
{
	if(m_nType != CT_STR)
		new(m_vBuf)string();
	m_nType = CT_STR;
	*(string*)m_vBuf = _Value;
}

//template< typename T > 
void Variant::WriteMemory( void* _pAddr ) const
{
	switch( m_nType )
	{
	case	CT_INT:			Assign<int>(_pAddr,m_vBuf); break;
	case	CT_FLOAT:		Assign<float>(_pAddr,m_vBuf); break;
	case	CT_STR:			Assign<string>(_pAddr,m_vBuf); break;
	};
}

void Variant::ReadMemory( const void* _pAddr )
{
	switch( m_nType )
	{
	case	CT_INT:			Set((*(int*)_pAddr)); break;
	case	CT_FLOAT:		Set((*(float*)_pAddr)); break;
	case	CT_STR:			Set(((string*)_pAddr)->c_str()); break;
	};
}

Variant::Variant( int _Value )
{
	m_nType = CT_INT;
	*(int*)m_vBuf = _Value;
}

Variant::Variant( float _Value )
{
	m_nType = CT_FLOAT;
	*(float*)m_vBuf = _Value;
}


Variant::Variant( const char* _Value )
{
	new(m_vBuf)string();
	m_nType = CT_STR;
	*(string*)m_vBuf = _Value;
}
